Inside Macintosh: Memory

Previous | Chapter Top | Chapter Contents | Next

Defining a Grow-Zone Function

The Memory Manager calls your heap's grow-zone function only after other attempts to obtain enough memory to satisfy a memory allocation request have failed. A grow-zone function should be of the following form:

FUNCTION MyGrowZone (cbNeeded: Size): LongInt;

The Memory Manager passes to your function (in the cbNeeded parameter) the number of bytes it needs. Your function can do whatever it likes to free that much space in the heap. For example, your grow-zone function might dispose of certain blocks or make some unpurgeable blocks purgeable. Your function should return the number of bytes, if any, it managed to free.

When the function returns, the Memory Manager once again purges and compacts the heap and tries again to allocate the requested amount of memory. If there is still insufficient memory, the Memory Manager calls your grow-zone function again, but only if the function returned a nonzero value when last called. This mechanism allows your grow-zone function to release memory gradually; if the amount it releases is not enough, the Memory Manager calls it again and gives it the opportunity to take more drastic measures.

Typically a grow-zone function frees space by calling the EmptyHandle procedure, which purges a relocatable block from the heap and sets the block's master pointer to NIL . This is preferable to disposing of the space (by calling the DisposeHandle procedure), because you are likely to want to reallocate the block.

The Memory Manager might designate a particular relocatable block in the heap as protected; your grow-zone function should not move or purge that block. You can determine which block, if any, the Memory Manager has protected by calling the GZSaveHnd function in your grow-zone function.

Listing 1-13 defines a very basic grow-zone function. The MyGrowZone function attempts to create space in the application heap simply by releasing the block of emergency memory. First, however, it checks that (1) the emergency memory hasn't already been released and (2) the emergency memory is not a protected block of memory (as it would be, for example, during an attempt to reallocate the emergency memory block). If either of these conditions isn't true, then MyGrowZone returns 0 to indicate that no memory was released.

Listing 13 A grow-zone function that releases emergency storage

FUNCTION MyGrowZone (cbNeeded: Size): LongInt;
VAR
    theA5:      LongInt;                    {value of A5 when function is called}
BEGIN
    theA5 := SetCurrentA5;                  {remember current value of A5; install ours}
    IF (gEmergencyMemory^ <> NIL) & (gEmergencyMemory <> GZSaveHnd) THEN
        BEGIN
            EmptyHandle(gEmergencyMemory);
            MyGrowZone := kEmergencyMemorySize;
        END
    ELSE
        MyGrowZone := 0;                    {no more memory to release}
    theA5 := SetA5(theA5);                  {restore previous value of A5}
END;

The function MyGrowZone defined in Listing 1-13 saves the current value of the A5 register when it begins and then restores the previous value before it exits. This is necessary because your grow-zone function might be called at a time when the system is attempting to allocate memory and value in the A5 register is not correct. See the chapter "Memory Management Utilities" in this book for more information about saving and restoring the A5 register.

You need to save and restore the A5 register only if your grow-zone function accesses your A5 world. (In Listing 1-13 , the grow-zone function uses the global variable gEmergencyMemory .)


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next